package com.pine.manager.core;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.reflect.GenericTypeUtils;
import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.pine.common.beans.request.PageRequest;
import com.pine.common.convertor.EntityConvertor;
import com.pine.common.database.BaseMapper;
import com.pine.common.database.entity.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ObjectUtils;

import java.io.Serializable;
import java.util.*;

/**
 * 基础管理类
 *
 * @author pine manage
 * @since 2024-08-09
 */
public class BaseManager<Mapper extends BaseMapper<Entity>, Entity extends BaseEntity<ID>, ID extends Serializable, EntityBo extends Entity, Query extends BaseQuery<ID>, Convertor extends EntityConvertor<Entity, EntityBo>> {

    @Autowired
    @Getter
    protected Mapper mapper;

    @Autowired
    protected Convertor entityConvertor;

    /**
     * BaseManager的范型类型
     */
    protected final Class<?>[] typeArguments = GenericTypeUtils.resolveTypeArguments(this.getClass(), BaseManager.class);

    /**
     * Mapper 的类型
     */
    protected Class<Mapper> mapperClass = this.currentMapperClass();

    @Setter
    @Getter
    protected int batchSize;
    protected static final int DEFAULT_BATCH_SIZE = 100;
    protected static final String ASC = "asc";
    protected static final String DESC = "desc";

    protected static final String DEFAULT_ORDER_BY_FIELD = "id";

    public BaseManager() {
        this.batchSize = DEFAULT_BATCH_SIZE;
    }

    @SuppressWarnings("unchecked")
    protected Class<Mapper> currentMapperClass() {
        return (Class<Mapper>) this.typeArguments[0];
    }

    /**
     * 保存
     *
     * @param entity 实体
     * @return 是否保存成功
     */
    public <E extends Entity> boolean save(E entity) {
        return this.mapper.insert(entity) > 0;
    }

    /**
     * 批量保存
     *
     * @param entityList 实体列表
     */
    public <E extends Entity> void saveBatch(Collection<E> entityList) {
        if (!ObjectUtils.isEmpty(entityList)) {
            this.mapper.insertBatchSomeColumn(new ArrayList<>(entityList), this.batchSize);
        }
    }

    /**
     * 批量保存
     *
     * @param entityList 实体列表
     * @param batchSize 批量大小
     */
    public <E extends Entity> void saveBatch(Collection<E> entityList, int batchSize) {
        if (!ObjectUtils.isEmpty(entityList)) {
            this.mapper.insertBatchSomeColumn(new ArrayList<>(entityList), Math.max(batchSize, this.batchSize));
        }
    }

    /**
     * 根据ID更新
     *
     * @param entity 实体
     * @return 是否更新成功
     */
    public <E extends Entity> boolean updateById(E entity) {
        return this.mapper.updateById(entity) > 0;
    }

    /**
     * 根据ID删除
     *
     * @param id id
     * @return 是否删除成功
     */
    public boolean deleteById(ID id) {
        return this.mapper.deleteById(id) > 0;
    }

    /**
     * 根据ID批量删除
     *
     * @param ids id集合
     * @return 是否删除成功
     */
    public boolean deleteById(Collection<ID> ids) {
        return this.mapper.deleteBatchIds(ids) > 0;
    }

    /**
     * 根据条件删除
     *
     * @param queryWrapper 条件
     * @return 是否删除成功
     */
    public boolean delete(Wrapper<Entity> queryWrapper) {
        return mapper.delete(queryWrapper) > 0;
    }


    /**
     * 根据查询条件查询单条数据
     *
     * @param query 查询条件
     * @return 业务对象
     */
    public EntityBo getOne(Query query) {
        LambdaQueryWrapper<Entity> queryWrapper = this.encapsulateQueryWrapper(query);
        queryWrapper.last(" limit 1");
        Entity entity = this.mapper.selectOne(queryWrapper);
        return entityConvertor.entityToEntityBo(entity);
    }

    /**
     * 通过唯一键查询单条数据
     *
     * @param uniqueKey 唯一键
     * @return 业务对象
     */
    public EntityBo getOneByUniqueKey(Object uniqueKey, SFunction<Entity, ?> column) {
        LambdaQueryWrapper<Entity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(column, uniqueKey);
        return getOne(queryWrapper);
    }

    /**
     * 通过查询条件查询单条数据
     *
     * @param queryWrapper 查询条件
     * @return 业务对象
     */
    public EntityBo getOne(LambdaQueryWrapper<Entity> queryWrapper) {
        // 查询单条数据
        Entity entity = this.mapper.selectOne(queryWrapper, true);

        // 根据查询结果转换业务对象
        return entityConvertor.entityToEntityBo(entity);
    }

    /**
     * 封装查询条件
     *
     * @param query 请求参数
     * @return 查询条件wrapper
     */
    protected LambdaQueryWrapper<Entity> encapsulateQueryWrapper(Query query) {
        QueryWrapper<Entity> wrapper = new QueryWrapper<>();
        if (Objects.isNull(query)) {
            return wrapper.lambda();
        }

        // 处理查询字段
        String[] underLineFields = query.convertToUnderLineFields();
        if (Objects.nonNull(underLineFields) && underLineFields.length > 0) {
            wrapper.select(underLineFields);
        }

        // 处理排序规则
        String orderBy = query.getOrderBy();
        if (StrUtil.isNotBlank(orderBy)) {
            String[] orderByExpressions = orderBy.split(StrUtil.COMMA);
            List<String> ascFields = new ArrayList<>();
            List<String> descFields = new ArrayList<>();
            for (String orderByExpression : orderByExpressions) {
                if (orderByExpression.endsWith(ASC)) {
                    ascFields.add(orderByExpression.replace(StrUtil.DASHED + ASC, StrUtil.EMPTY));
                    continue;
                }
                if (orderByExpression.endsWith(DESC)) {
                    descFields.add(orderByExpression.replace(StrUtil.DASHED + DESC, StrUtil.EMPTY));
                }
            }

            // 没有排序规则，使用ID倒序排序
            if (CollUtil.isEmpty(descFields) && CollUtil.isEmpty(ascFields)) {
                wrapper.orderByDesc(DEFAULT_ORDER_BY_FIELD);
            } else {
                if (CollUtil.isNotEmpty(ascFields)) {
                    wrapper.orderByAsc(ascFields);
                }
                if (CollUtil.isNotEmpty(descFields)) {
                    wrapper.orderByDesc(descFields);
                }
            }
        } else {
            // 没有排序规则，使用ID倒序排序
            wrapper.orderByDesc(DEFAULT_ORDER_BY_FIELD);
        }

        LambdaQueryWrapper<Entity> lambda = wrapper.lambda();
        lambda.eq(Objects.nonNull(query.getId()), Entity::getId, query.getId());
        lambda.in(CollUtil.isNotEmpty(query.getIdList()), Entity::getId, query.getIdList());
        lambda.ge(Objects.nonNull(query.getCreateTimeStart()), Entity::getCreateTime, query.getCreateTimeStart());
        lambda.le(Objects.nonNull(query.getCreateTimeEnd()), Entity::getCreateTime, query.getCreateTimeEnd());
        return lambda;
    }

    /**
     * 分页查询实现
     *
     * @param request 请求参数
     * @return 响应结果
     */
    public IPage<EntityBo> page(PageRequest<Query> request) {
        // 组装查询条件
        LambdaQueryWrapper<Entity> queryWrapper = encapsulateQueryWrapper(request.getData());

        // 分页查数据
        Page<Entity> objectPage = new Page<>(request.getPageNum(), request.getPageSize());
        // 设置禁止自动获取总数并手动查询总数
        objectPage.setSearchCount(false);
        Long selectedCount = mapper.selectCount(queryWrapper);
        objectPage.setTotal(selectedCount);
        Page<Entity> entityPage = this.mapper.selectPage(objectPage, queryWrapper);

        // 根据查询结果组装业务对象列表
        List<EntityBo> entityBos = entityConvertor.entityToEntityBo(entityPage.getRecords());

        // 返回业务分页结果
        return Page.<EntityBo>of(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal(), entityPage.searchCount()).setRecords(entityBos);
    }

    /**
     * 查询列表
     *
     * @param queryWrapper 查询条件
     * @return 实体Bo列表
     */
    public List<EntityBo> list(Wrapper<Entity> queryWrapper) {
        List<Entity> entities = this.mapper.selectList(queryWrapper);
        return entityConvertor.entityToEntityBo(entities);
    }

    /**
     * 通过主键列表查询实体列表
     *
     * @param primaryKeys 主键列表
     * @return 实体Bo列表
     */
    public List<EntityBo> listByPrimaryKeys(List<ID> primaryKeys) {
        if (CollUtil.isEmpty(primaryKeys)) {
            return Collections.emptyList();
        }
        List<Entity> entities = this.mapper.selectBatchIds(primaryKeys);
        return entityConvertor.entityToEntityBo(entities);
    }

    /**
     * 查询列表
     *
     * @param query 查询条件
     * @return 实体Bo列表
     */
    public List<EntityBo> list(Query query) {
        List<Entity> entities = this.mapper.selectList(encapsulateQueryWrapper(query));
        return entityConvertor.entityToEntityBo(entities);
    }
}
